#include "QmitkPointListWidget.h"
#include <mitkGlobalInteraction.h>
#include <mitkPointSetReader.h>
#include <mitkPointSetWriter.h>

#include <QHBoxLayout>
#include <QFileDialog>
#include <QMessageBox>
#include <QDir>

#include "btnLoad.xpm"
#include "btnSave.xpm"
#include "btnClear.xpm"
#include "btnSetPoints.xpm"
#include "btnUp.xpm"
#include "btnDown.xpm"



QmitkPointListWidget::QmitkPointListWidget(QWidget *parent, int orientation):
        QWidget(parent), m_PointListView(NULL),  m_MultiWidget(NULL),  m_PointSetNode(NULL), m_Orientation(0),  m_MovePointUpBtn(NULL),
        m_MovePointDownBtn(NULL), m_RemovePointBtn(NULL), m_SavePointsBtn(NULL), m_LoadPointsBtn(NULL), m_ToggleAddPoint(NULL),
                m_Interactor(NULL), m_TimeStep(0), m_EditAllowed(true), m_NodeObserverTag(0)
{
    m_PointListView = new QmitkPointListView();

    if(orientation != 0)
        m_Orientation = orientation;

    SetupUi();
    SetupConnections();
    ObserveNewNode(NULL);

}

QmitkPointListWidget::~QmitkPointListWidget()
{
    if (m_Interactor)
        mitk::GlobalInteraction::GetInstance()->RemoveInteractor( m_Interactor );
    m_Interactor = NULL;

    if(m_PointSetNode && m_NodeObserverTag)
    {
      m_PointSetNode->RemoveObserver(m_NodeObserverTag);
      m_NodeObserverTag = 0;
    }

    m_MultiWidget = NULL;
    delete m_PointListView;
}


void QmitkPointListWidget::SetupConnections()
{
    //m_PointListView->setModel(m_PointListModel);

    connect(this->m_LoadPointsBtn, SIGNAL(clicked()), this, SLOT(OnBtnLoadPoints()));
    connect(this->m_SavePointsBtn, SIGNAL(clicked()), this, SLOT(OnBtnSavePoints()));
    connect(this->m_MovePointUpBtn, SIGNAL(clicked()), this, SLOT(MoveSelectedPointUp()));
    connect(this->m_MovePointDownBtn, SIGNAL(clicked()), this, SLOT(MoveSelectedPointDown()));
    connect(this->m_RemovePointBtn, SIGNAL(clicked()), this, SLOT(RemoveSelectedPoint()));
    connect(this->m_ToggleAddPoint, SIGNAL(toggled(bool)), this, SLOT(OnBtnAddPoint(bool)));
    connect(this->m_PointListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnListDoubleClick()));
    connect(this->m_PointListView, SIGNAL(SignalPointSelectionChanged()), this, SLOT(OnPointSelectionChanged()));
}

void QmitkPointListWidget::SetupUi()
{
    //Setup the buttons

    m_ToggleAddPoint = new QPushButton();//iconSetPoints, "", this);
    m_ToggleAddPoint->setMaximumSize(25,25);
    m_ToggleAddPoint->setCheckable(true);
	m_ToggleAddPoint->setToolTip(QString::fromLocal8Bit("从影像中选取点（使用SHIFT  + 鼠标左键添加点）"));
    QIcon iconAdd(btnSetPoints_xpm);
    m_ToggleAddPoint->setIcon(iconAdd);

    m_RemovePointBtn = new QPushButton();
    m_RemovePointBtn->setMaximumSize(25, 25);
    const QIcon iconDel(btnClear_xpm);
    m_RemovePointBtn->setIcon(iconDel);
    m_RemovePointBtn->setToolTip(QString::fromLocal8Bit("从点集中删除一个点（热键：DEL）"));


    m_MovePointUpBtn = new QPushButton();
    m_MovePointUpBtn->setMaximumSize(25, 25);
    const QIcon iconUp(btnUp_xpm);
    m_MovePointUpBtn->setIcon(iconUp);
    m_MovePointUpBtn->setToolTip(QString::fromLocal8Bit("向上移动选中点（热键：F2）"));

    m_MovePointDownBtn = new QPushButton();
    m_MovePointDownBtn->setMaximumSize(25, 25);
    const QIcon iconDown(btnDown_xpm);
    m_MovePointDownBtn->setIcon(iconDown);
    m_MovePointDownBtn->setToolTip(QString::fromLocal8Bit("向下移动选中点（热键：F3）"));

    m_SavePointsBtn = new QPushButton();
    m_SavePointsBtn->setMaximumSize(25, 25);
    QIcon iconSave(btnSave_xpm);
    m_SavePointsBtn->setIcon(iconSave);
    m_SavePointsBtn->setToolTip(QString::fromLocal8Bit("保存点集到文件"));

    m_LoadPointsBtn = new QPushButton();
    m_LoadPointsBtn->setMaximumSize(25, 25);
    QIcon iconLoad(btnLoad_xpm);
    m_LoadPointsBtn->setIcon(iconLoad);
    m_LoadPointsBtn->setToolTip(QString::fromLocal8Bit("从文件中加载点集（替换当前点集）"));


    int i;

      QBoxLayout* lay1;
      QBoxLayout* lay2;

      switch (m_Orientation)
      {
      case 0:
          lay1 = new QVBoxLayout(this);
          lay2 = new QHBoxLayout();
          i = 0;
          break;

      case 1:
          lay1 = new QHBoxLayout(this);
          lay2 = new QVBoxLayout();
          i=-1;
          break;

      case 2:
          lay1 = new QHBoxLayout(this);
          lay2 = new QVBoxLayout();
          i=0;
          break;

      default:
          lay1 = new QVBoxLayout(this);
          lay2 = new QHBoxLayout();
          i=-1;
          break;

      }

      //setup Layouts

      this->setLayout(lay1);
      lay1->addLayout(lay2);

      lay2->stretch(true);
      lay2->addWidget(m_ToggleAddPoint);
      lay2->addWidget(m_RemovePointBtn);
      lay2->addWidget(m_MovePointUpBtn);
      lay2->addWidget(m_MovePointDownBtn);
      lay2->addWidget(m_SavePointsBtn);
      lay2->addWidget(m_LoadPointsBtn);


      //lay2->addSpacing();;

      lay1->insertWidget(i,m_PointListView);
      this->setLayout(lay1);
}

void QmitkPointListWidget::SetPointSet(mitk::PointSet* newPs)
{
  if(newPs == NULL)
    return;

  this->m_PointSetNode->SetData(newPs);
  dynamic_cast<QmitkPointListModel*>(this->m_PointListView->model())->SetPointSetNode(m_PointSetNode);
  ObserveNewNode(m_PointSetNode);
}

void QmitkPointListWidget::SetPointSetNode(mitk::DataNode *newNode)
{

  ObserveNewNode(newNode);
  if (newNode != NULL)
    dynamic_cast<QmitkPointListModel*>(this->m_PointListView->model())->SetPointSetNode(newNode);
  else
    dynamic_cast<QmitkPointListModel*>(this->m_PointListView->model())->SetPointSetNode(NULL);
}

void QmitkPointListWidget::OnBtnSavePoints()
{
    if ((dynamic_cast<mitk::PointSet*>(m_PointSetNode->GetData()))  == NULL)
        return; // don't write empty point sets. If application logic requires something else then do something else.
    if ((dynamic_cast<mitk::PointSet*>(m_PointSetNode->GetData()))->GetSize() == 0)
        return;

    // let the user choose a file
    std::string name("");

    QString fileNameProposal = QString("/PointSet.mps");//.arg(m_PointSetNode->GetName().c_str()); //"PointSet.mps";
    QString aFilename = QFileDialog::getSaveFileName( NULL, "Save point set", QDir::currentPath() + fileNameProposal, "MITK Pointset (*.mps)" );
    if ( aFilename.isEmpty() )
        return;

    try
    {
        // instantiate the writer and add the point-sets to write
        mitk::PointSetWriter::Pointer writer = mitk::PointSetWriter::New();
        writer->SetInput( dynamic_cast<mitk::PointSet*>(m_PointSetNode->GetData()) );
        writer->SetFileName( aFilename.toLatin1() );
        writer->Update();
    }
    catch(...)
    {
        QMessageBox::warning( this, "Save point set",
                              QString("File writer reported problems writing %1\n\n"
                                      "PLEASE CHECK output file!").arg(aFilename) );
    }
}

void QmitkPointListWidget::OnBtnLoadPoints()
{
    // get the name of the file to load
    QString filename = QFileDialog::getOpenFileName( NULL, "Open MITK Pointset", "", "MITK Point Sets (*.mps)");
    if ( filename.isEmpty() ) return;

    // attempt to load file
    try
    {
        mitk::PointSetReader::Pointer reader = mitk::PointSetReader::New();
        reader->SetFileName( filename.toLatin1() );
        reader->Update();

        mitk::PointSet::Pointer pointSet = reader->GetOutput();
        if ( pointSet.IsNull() )
        {
            QMessageBox::warning( this, "Load point set", QString("File reader could not read %1").arg(filename) );
            return;
        }

        // loading successful

        //      bool interactionOn( m_Interactor.IsNotNull() );
        //      if (interactionOn)
        //      {
        //        OnEditPointSetButtonToggled(false);
        //      }
        //
        this->SetPointSet(pointSet);
        //      if (interactionOn)
        //      {
        //        OnEditPointSetButtonToggled(true);
        //      }
    }
    catch(...)
    {
        QMessageBox::warning( this, "Load point set", QString("File reader collapsed while reading %1").arg(filename) );
    }
    emit PointListChanged();
    mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

mitk::PointSet* QmitkPointListWidget::GetPointSet()
{
    return dynamic_cast<mitk::PointSet*>(m_PointSetNode->GetData());
}

mitk::DataNode* QmitkPointListWidget::GetPointSetNode()
{
    return m_PointSetNode;
}

void QmitkPointListWidget::SetMultiWidget(QmitkStdMultiWidget *multiWidget)
{
    this->m_MultiWidget = multiWidget;
    m_PointListView->SetMultiWidget(multiWidget);
}

void QmitkPointListWidget::RemoveSelectedPoint()
{

    if (!m_PointSetNode) return;
    mitk::PointSet* pointSet = dynamic_cast<mitk::PointSet*>( m_PointSetNode->GetData() );
    if (!pointSet) return;
    if (pointSet->GetSize() == 0) return;

    QmitkPointListModel* pointListModel = dynamic_cast<QmitkPointListModel*>( m_PointListView->model() );
    pointListModel->RemoveSelectedPoint();
    emit PointListChanged();
}

void QmitkPointListWidget::MoveSelectedPointDown()
{

    if (!m_PointSetNode) return;
    mitk::PointSet* pointSet = dynamic_cast<mitk::PointSet*>( m_PointSetNode->GetData() );
    if (!pointSet) return;
    if (pointSet->GetSize() == 0) return;

    QmitkPointListModel* pointListModel = dynamic_cast<QmitkPointListModel*>( m_PointListView->model() );
    pointListModel->MoveSelectedPointDown();
    emit PointListChanged();
}

void QmitkPointListWidget::MoveSelectedPointUp()
{

    if (!m_PointSetNode) return;
    mitk::PointSet* pointSet = dynamic_cast<mitk::PointSet*>( m_PointSetNode->GetData() );
    if (!pointSet) return;
    if (pointSet->GetSize() == 0) return;

    QmitkPointListModel* pointListModel = dynamic_cast<QmitkPointListModel*>( m_PointListView->model() );
    pointListModel->MoveSelectedPointUp();
    emit PointListChanged();
}

void QmitkPointListWidget::OnBtnAddPoint(bool checked)
{
    if (m_PointSetNode)
    {
        if (checked)
        {
          m_Interactor = dynamic_cast<mitk::PointSetInteractor*>(m_PointSetNode->GetInteractor());
          
          if (m_Interactor.IsNull())//if not present, instanciate one
            m_Interactor = mitk::PointSetInteractor::New("pointsetinteractor", m_PointSetNode);
          
          //add it to global interaction to activate it
          mitk::GlobalInteraction::GetInstance()->AddInteractor( m_Interactor );
        }
        else if ( m_Interactor )
        {
            mitk::GlobalInteraction::GetInstance()->RemoveInteractor( m_Interactor );
            m_Interactor = NULL;
        }
        emit EditPointSets(checked);
        mitk::BaseRenderer::GetInstance(m_MultiWidget->mitkWidget4->GetRenderWindow())->RequestUpdate();
    }
}

//void QmitkPointListWidget::SetMultiWidget(QmitkStdMultiWidget *multiWidget)
//{
//    this->m_MultiWidget = multiWidget;
//    this->m_PointListView->SetMultiWidget(multiWidget);
//}



void QmitkPointListWidget::OnListDoubleClick()
{
    ;
}

void QmitkPointListWidget::OnPointSelectionChanged()
{
  emit this->PointSelectionChanged();
}

void QmitkPointListWidget::DeactivateInteractor(bool /*deactivate*/)
{
    ;
}

void QmitkPointListWidget::EnableEditButton( bool enabled )
{
  m_EditAllowed = enabled;
  if (enabled == false)
    m_ToggleAddPoint->setEnabled(false);
  else
    m_ToggleAddPoint->setEnabled(true);
  OnBtnAddPoint(enabled);
}


void QmitkPointListWidget::ObserveNewNode( mitk::DataNode* node )
{
  // remove old observer
  if ( m_PointSetNode )
  {
    if (m_Interactor)
    {
      mitk::GlobalInteraction::GetInstance()->RemoveInteractor( m_Interactor );
      m_Interactor = NULL;
      m_ToggleAddPoint->setChecked( false );
    }

    m_PointSetNode->RemoveObserver( m_NodeObserverTag );
    m_NodeObserverTag = 0;
  }

  m_PointSetNode = node;

  // add new observer if necessary
  if ( m_PointSetNode )
  {
    itk::ReceptorMemberCommand<QmitkPointListWidget>::Pointer command = itk::ReceptorMemberCommand<QmitkPointListWidget>::New();
    command->SetCallbackFunction( this, &QmitkPointListWidget::OnNodeDeleted );
    m_NodeObserverTag = m_PointSetNode->AddObserver( itk::DeleteEvent(), command );
  }
  else
  {
    m_NodeObserverTag = 0;
  }

  if (m_EditAllowed == true)
    m_ToggleAddPoint->setEnabled( m_PointSetNode );
  else
    m_ToggleAddPoint->setEnabled( false );

  m_RemovePointBtn->setEnabled( m_PointSetNode );
  m_LoadPointsBtn->setEnabled( m_PointSetNode );
  m_LoadPointsBtn->setEnabled( m_PointSetNode );
}

void QmitkPointListWidget::SetAddPointToggle(bool checked)
{
    m_ToggleAddPoint->setChecked(checked);
}

void QmitkPointListWidget::OnNodeDeleted( const itk::EventObject &  /*e*/ )
{
  if(m_PointSetNode.IsNotNull() && ! m_NodeObserverTag)
      m_PointSetNode->RemoveObserver( m_NodeObserverTag );
  m_NodeObserverTag = 0;
  m_PointSetNode = NULL;
  m_PointListView->SetPointSetNode(NULL);
  m_ToggleAddPoint->setEnabled(false);

  m_RemovePointBtn->setEnabled( m_PointSetNode );
  m_LoadPointsBtn->setEnabled( m_PointSetNode );
  m_LoadPointsBtn->setEnabled( m_PointSetNode );
}

